﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PowerCalculation
{
    public class PowerCalculator
    {
        const float Voltage = 0xdc;
        const float DiversityFactor = (float)0.7;
        public List<ElectroData> ElectroDataList;
        public WireData WireData;
        public int GroupsCount { get; set; }
        public int ChangeSection { get; set; } // 1- изменено, 2-изменить невозможно
        public float GroupsPower { get; set; }

       // public int FloorCount { get; set; }
       // public int EntranceCount { get; set; }

        public float CableLength { get; set; }



        public PowerCalculator(List<ElectroData> electroDataList, WireData cableData, int floorCount, int entranceCount)
        {
            ElectroDataList = electroDataList;
            WireData = cableData;

            CalculateCableLangth(floorCount, entranceCount);

            DivideIntoGroups();
            DivideIntoGroupsReglaments();

        }

        float GroupPower(int groupId)
        {
            return ElectroDataList.Where(consumer => consumer.GroupId == groupId).Select(consumer=>consumer.ConsumerPower).Sum();
        }

        public float? FindAutomatAmperage(int groupId)
        {
            float groupPower = GroupPower(groupId);
            if (groupPower != null)
                return (float?)ElectricRepoStore.GetRepository().GetAutomatByPower(groupPower).AutomateAmperage;
            else return null;
        }

        void CalculateCableLangth(int floorC, int entranceC)
        {
            CableLength = entranceC*10 + floorC*3;
        }

        public float TotalLampsPower()
        {
            return ElectroDataList.Where(consumer => consumer.IsLamp).Select(consumer => consumer.ConsumerPower).Sum();
        }

        
        float TotalElectricPowerWithoutReglaments()
        {
            return ElectroDataList.Where(consumer => !consumer.IsLamp && consumer.ReglamentWireId == null).Select(consumer => consumer.ConsumerPower).Sum();
        }

        public float TotalElectricPower()
        {
            return ElectroDataList.Where(consumer => !consumer.IsLamp).Select(consumer => consumer.ConsumerPower).Sum();
        }

        float TotalAmperageWithoutReglaments()
        {
            return ((TotalElectricPowerWithoutReglaments() + TotalLampsPower()) * 1000) / Voltage * DiversityFactor;
        }

        public float TotalPower()
        {
            return TotalElectricPower() + TotalLampsPower();
        }

        public float TotalAmperage()
        {
            return ((TotalElectricPower() + TotalLampsPower()) * 1000) / Voltage * DiversityFactor;
        }

        float TotalCableAmperage()
        {
            return WireData.WireAmperage();
        }

        float SumInGroup(int groupNo)
        {
            return ElectroDataList.Where(consumer => consumer.GroupId == groupNo).Select(consumer => consumer.ConsumerPower).
                Sum();
        }

        int MinSumGroup(int groupsCount)
        {
            float min = SumInGroup(0);
            int minGroupIndex = 0;
            for (int electroIndexGroup = 0; electroIndexGroup < groupsCount; electroIndexGroup++)
            {
                if (SumInGroup(electroIndexGroup) < min)
                {
                    min = SumInGroup(electroIndexGroup);
                    minGroupIndex = electroIndexGroup;
                }
            }
            return minGroupIndex;
        }

        int GroupsCountFunction()
        {
            float totalAmperage = TotalAmperageWithoutReglaments();
            float totalCableAmperage = TotalCableAmperage();
            return (int)Math.Round(totalAmperage / totalCableAmperage) + 1;
        }

        public void DivideIntoGroupsReglaments()
        {
            foreach (var electroReg in ElectroDataList.Where(el => el.ReglamentWireId != null))
            {
                electroReg.GroupId = GroupsCount;
                GroupsCount++;

            }
        }

        public void DivideIntoGroups()
        {
            
            ChangeSection = IsError();
            GroupsCount = GroupsCountFunction();
            if (ChangeSection != 2)
            {
                if (GroupsCount != 1)
                    for (int electroIndex = 0; electroIndex < ElectroDataList.Where(n=>n.ReglamentWireId == null).ToList().Count; electroIndex++)
                    {
                        if (electroIndex < GroupsCount)
                            ElectroDataList[electroIndex].GroupId = electroIndex;
                        else
                        {
                          if (BalanceIngroup(MinSumGroup(GroupsCount)) > ElectroDataList[electroIndex].ConsumerPower)
                            {
                                ElectroDataList[electroIndex].GroupId = MinSumGroup(GroupsCount);
                            }
                            else
                            {
                                GroupsCount++;
                                electroIndex--;
                            }
                        }
                    }

                else
                    ElectroDataList.ForEach(consumer => { consumer.GroupId = 0; });
            }
            else
            {
                GroupsCount = 0;
            }
        }

        // остаток по мощности в группе
        float BalanceIngroup(int groupId)
        {
            float powerInGroup = 0;
            ElectroDataList.Where(n => n.GroupId == groupId).ToList().ForEach(n => { powerInGroup += n.ConsumerPower; });
            return WireData.WireAmperage()*220/1000 - powerInGroup;
        }

        bool IsOneOfTheConsumersLargerThanCore()
        {
            float wirePower = WireData.WireAmperage()*220/1000;
            bool isLargerThanCore = false;
            ElectroDataList.Where(n => n.ReglamentWireId == null).ToList().ForEach(n =>
            {
                if (n.ConsumerPower >
                    wirePower)
                    isLargerThanCore = true; 
            });
            return isLargerThanCore;
        }

        //-1 - верно, 1 - изменено, 2- изменить невозможно
        public int IsError()
        {

            if (IsOneOfTheConsumersLargerThanCore())
            {
                                                                                                                       
                //сечение провода не удовлетворяет условиям
                //Попытки проложить другой провод
                foreach (var wire in ElectricRepoStore.GetRepository().GetWires())
                {
                    if (wire.WireMaterialId == WireData.WireMaterial)
                    {
                        if (wire.WireSectionId != null)
                        {
                            WireData.WireSection = (int) wire.WireSectionId;
                            WireData.WireCoreCount = (int) wire.WireCoreCount;
                        }
                        if (!IsOneOfTheConsumersLargerThanCore())
                        {
                            ChangeSection = 1;
                            return 1;
                            
                        }
                    }
                }
                ChangeSection = 2;
                return 2;

            }
            return -1;

        }

    }

}
